package com.brainhealth.customer.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.brainhealth.common.constant.Constants;
import com.brainhealth.common.constant.NumberConstants;
import com.brainhealth.common.enums.*;
import com.brainhealth.common.utils.DateCalcUtils;
import com.brainhealth.common.utils.DateUtils;
import com.brainhealth.customer.config.MinioConfig;
import com.brainhealth.customer.domain.*;
import com.brainhealth.customer.domain.vo.CustomerExerciseVO;
import com.brainhealth.customer.domain.vo.CustomerReportVO;
import com.brainhealth.customer.domain.vo.FinishExerciseVO;
import com.brainhealth.customer.mapper.*;
import com.brainhealth.customer.service.*;
import com.brainhealth.utils.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 会员训练记录Service业务层处理
 *
 * @author wolong
 * @date 2023-05-09
 */
@Service
public class CustomerExerciseServiceImpl implements ICustomerExerciseService {
    private static final Logger logger = LoggerFactory.getLogger(CustomerExerciseServiceImpl.class);

    @Autowired
    private CustomerExerciseMapper customerExerciseMapper;
    @Autowired
    private ExerciseMapper exerciseMapper;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private CustomerScoreMapper customerScoreMapper;
    @Autowired
    private CustomerReportTimeMapper customerReportTimeMapper;
    @Autowired
    private CustomerReportCycleMapper customerReportCycleMapper;
    @Autowired
    private ExerciseOrderMapper exerciseOrderMapper;
    @Autowired
    private CustomerDifficultyMapper customerDifficultyMapper;
    @Autowired
    private ChatRecordMapper chatRecordMapper;
    @Autowired
    private IExerciseOrderService exerciseOrderService;
    @Autowired
    private ChatMainMapper chatMainMapper;
    @Autowired
    MinioConfig minioConfig;
    @Autowired
    private ExerciseCategoryMapper exerciseCategoryMapper;
    @Autowired
    IScoreRecordService scoreRecordService;

    @Override
    public CustomerExercise getCustomerExercise(Customer customer, CustomerExerciseStatus status) {
        List<CustomerExercise> customerExerciseList = getCustomerExerciseList(customer, status);
        if (CollectionUtils.isEmpty(customerExerciseList)) {
            return null;
        }
        OptionalLong optionalLong = customerExerciseList.stream().mapToLong(CustomerExercise::getCustomerExerciseId).min();
        Long customerExerciseId = optionalLong.getAsLong();
        CustomerExercise customerExercise = customerExerciseList.stream().filter(item -> item.getCustomerExerciseId().equals(customerExerciseId)).collect(Collectors.toList()).get(0);

        return customerExercise;
    }

    /**
     * 查询会员训练记录
     *
     * @param customerExerciseId 会员训练记录主键
     * @return 会员训练记录
     */
    @Override
    public CustomerExercise selectCustomerExerciseByCustomerExerciseId(Long customerExerciseId) {
        return customerExerciseMapper.selectCustomerExerciseByCustomerExerciseId(customerExerciseId);
    }

    /**
     * 查询会员训练记录列表
     *
     * @param customerExercise 会员训练记录
     * @return 会员训练记录
     */
    @Override
    public List<CustomerExercise> selectCustomerExerciseList(CustomerExercise customerExercise) {
        return customerExerciseMapper.selectCustomerExerciseList(customerExercise);
    }

    public List<CustomerExercise> getCustomerExercises(Customer customer, CustomerExerciseStatus status) {
        ExerciseOrder exerciseOrderParam = new ExerciseOrder();
        exerciseOrderParam.setStatus(PayStatus.Exercise);
        ExerciseOrder exerciseOrder = exerciseOrderService.getCustomerExerciseOrder(customer, exerciseOrderParam);
        CustomerExercise customerExercise = new CustomerExercise();
        customerExercise.setCustomerId(customer.getCustomerId());
        customerExercise.setOrderId(exerciseOrder.getOrderId());
        customerExercise.setCountSort(1l);
        customerExercise.setExerciseType(1l);
        customerExercise.setStatus(status);
        List<CustomerExercise> customerExerciseList = selectCustomerExerciseList(customerExercise);
        if (CollectionUtils.isEmpty(customerExerciseList)) {
            logger.warn("未查询到该用户的训练记录，用户ID：{}，昵称：{}", customer.getCustomerId(), customer.getNickName());
            return null;
        }
        return customerExerciseList;
    }

    @Override
    public List<CustomerExercise> getCustomerExerciseList(Customer customer, CustomerExerciseStatus status) {
        ExerciseOrder exerciseOrderParam = new ExerciseOrder();
        exerciseOrderParam.setStatus(PayStatus.Exercise);
        ExerciseOrder exerciseOrder = exerciseOrderService.getCustomerExerciseOrder(customer, exerciseOrderParam);
        if (null == exerciseOrder) {
            exerciseOrderParam.setStatus(PayStatus.Finish);
            exerciseOrder = exerciseOrderService.getCustomerExerciseOrder(customer, exerciseOrderParam);
        }
        CustomerExercise customerExercise = new CustomerExercise();
        customerExercise.setCustomerId(customer.getCustomerId());
        customerExercise.setOrderId(exerciseOrder.getOrderId());
        customerExercise.setStatus(status);
        List<CustomerExercise> customerExerciseList = selectCustomerExerciseList(customerExercise);
        if (CollectionUtils.isEmpty(customerExerciseList)) {
            logger.warn("未查询到该用户的训练记录，用户ID：{}，昵称：{}，训练状态：{}", customer.getCustomerId(), customer.getNickName(), status.getInfo());
            return null;
        }
        return customerExerciseList;
    }

    @Override
    public List<CustomerExerciseVO> getCustomerExerciseListInfo(Customer customer) {
        NowCustomerExercise nowCustomerExercise = getNowCustomerExerciseList(customer);
        Exercise query = new Exercise();
        List<Exercise> lstExercise = exerciseMapper.selectExerciseList(query);
        List<CustomerExerciseVO> lstCustomerExerciseVO = new ArrayList<>();
        for (CustomerExercise customerExercise : nowCustomerExercise.getLstCustomerExercise()) {
            if (customerExercise.getExerciseType() == ExerciseType.Game.getCode()) {
                Exercise exercise = lstExercise.stream().filter(item -> item.getExerciseId().equals(customerExercise.getExerciseId())).findFirst().orElse(null);
                CustomerExerciseVO customerExerciseVO = new CustomerExerciseVO();
                customerExerciseVO.setCountSort(customerExercise.getCountSort());
                customerExerciseVO.setCustomerExerciseId(customerExercise.getCustomerExerciseId());
                customerExerciseVO.setExerciseImageUrl(exercise.getPictureUrl());
                customerExerciseVO.setExerciseUrl(exercise.getUrl());
                customerExerciseVO.setExerciseName(exercise.getName());
                customerExerciseVO.setStatus(customerExercise.getStatus());
                lstCustomerExerciseVO.add(customerExerciseVO);
            }
        }
        return lstCustomerExerciseVO;
    }

    /**
     * 新增会员训练记录
     *
     * @param customerExercise 会员训练记录
     * @return 结果
     */
    @Override
    public int insertCustomerExercise(CustomerExercise customerExercise) {
        customerExercise.setCreateTime(DateUtils.getNowDate());
        return customerExerciseMapper.insertCustomerExercise(customerExercise);
    }

    /**
     * 修改会员训练记录
     *
     * @param customerExercise 会员训练记录
     * @return 结果
     */
    @Override
    public int updateCustomerExercise(CustomerExercise customerExercise) {
        customerExercise.setUpdateTime(DateUtils.getNowDate());
        return customerExerciseMapper.updateCustomerExercise(customerExercise);
    }

    /**
     * 批量删除会员训练记录
     *
     * @param customerExerciseIds 需要删除的会员训练记录主键
     * @return 结果
     */
    @Override
    public int deleteCustomerExerciseByCustomerExerciseIds(Long[] customerExerciseIds) {
        return customerExerciseMapper.deleteCustomerExerciseByCustomerExerciseIds(customerExerciseIds);
    }

    /**
     * 删除会员训练记录信息
     *
     * @param customerExerciseId 会员训练记录主键
     * @return 结果
     */
    @Override
    public int deleteCustomerExerciseByCustomerExerciseId(Long customerExerciseId) {
        return customerExerciseMapper.deleteCustomerExerciseByCustomerExerciseId(customerExerciseId);
    }

    @Override
    public Exercise startCustomerExercise(HttpServletRequest request, Long customerExerciseId) {
        CustomerExercise customerExercise = customerExerciseMapper.selectCustomerExerciseByCustomerExerciseId(customerExerciseId);
        Customer customer = CommonUtils.getCustomerByRequest(request);
        //判断如果是白名单用户则
        if (customer.getMechanismId() == null) {
            Long hour = new Date().getTime() - customerExercise.getOpenTime().getTime();
            if (hour < 0) {
                return null;
            }
        }
        Exercise exercise = exerciseMapper.selectExerciseByExerciseId(customerExercise.getExerciseId());
        customerExercise.setStartTime(new Date());
        customerExerciseMapper.updateCustomerExercise(customerExercise);
        if (exercise.getExerciseType() == ExerciseType.Video) {
            exercise.setUrl(minioConfig.getAliyunOSS() + exercise.getUrl());
        }
        CustomerDifficulty customerDifficulty = customerDifficultyMapper.selectCustomerDifficultyByCustomerId(customerExercise.getCustomerId(), exercise.getExerciseId());
        if (customerDifficulty != null) {
            exercise.setDifficulty(customerDifficulty.getDifficulty());
        } else {
            exercise.setDifficulty(1l);
        }
        ExerciseCategory exerciseCategory = exerciseCategoryMapper.selectExerciseCategoryByExerciseCategoryId(exercise.getExerciseCategoryId());
        exercise.setExerciseCategoryName(exerciseCategory.getName());
        exercise.setExerciseCategoryDesc(exerciseCategory.getDescription());
        return exercise;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CustomerReportVO finishCustomerExercise(HttpServletRequest request, FinishExerciseVO finishExerciseVO) {
        logger.info("完成训练数据" + JSON.toJSONString(finishExerciseVO));
        Customer customer = CommonUtils.getCustomerByRequest(request);
        CustomerReportVO reportVo = new CustomerReportVO();
        try {
            CustomerExercise customerExercise = customerExerciseMapper.selectCustomerExerciseByCustomerExerciseId(finishExerciseVO.getCustomerExerciseId());
            if (customerExercise.getStatus() == CustomerExerciseStatus.Finished) {
                reportVo.setStatus(BusinessStatus.SUCCESS);
                logger.info("完成报告返回数据" + JSON.toJSONString(reportVo));
                return reportVo;
            }
            customerExercise.setEndTime(new Date());
            //判断是脑力训练还是视频训练，如果是脑力训练的话超过3分钟才算完成
            if (customerExercise.getExerciseType() == ExerciseType.Game.getCode()) {
                int minute = DateUtils.differentMinuteByMillisecond(new Date(), customerExercise.getStartTime());
                logger.info("完成游戏时间" + minute + "分钟");
                if (minute >= 1) {
                    customerExercise.setStatus(CustomerExerciseStatus.Finished);
                }
                if (customerExercise.getStartTime() != null) {
                    customerExercise.setExerciseTime((customerExercise.getEndTime().getTime() - customerExercise.getStartTime().getTime()) / 1000);
                }
                logger.info("完成游戏训练数据" + JSON.toJSONString(finishExerciseVO));
                logger.info("会员训练记录数据" + JSON.toJSONString(customerExercise));
            } else {
                //判断如果是视频训练根据前端获取的时间来判断训练时间
                if (finishExerciseVO.getExerciseTime() != null) {
                    customerExercise.setExerciseTime(finishExerciseVO.getExerciseTime());
                }
                customerExercise.setStatus(CustomerExerciseStatus.Finished);
            }
            if (finishExerciseVO.getResultValue() != null) {
                customerExercise.setResultValue(finishExerciseVO.getResultValue());
            }
            if (finishExerciseVO.getDifficulty() != null) {
                CustomerDifficulty customerDifficulty = customerDifficultyMapper.selectCustomerDifficultyByCustomerId(customer.getCustomerId(), customerExercise.getExerciseId());
                if (customerDifficulty != null) {
                    customerDifficulty.setDifficulty(finishExerciseVO.getDifficulty());
                    customerDifficultyMapper.updateCustomerDifficulty(customerDifficulty);
                } else {
                    CustomerDifficulty newCustomerDifficulty = new CustomerDifficulty();
                    newCustomerDifficulty.setDifficulty(finishExerciseVO.getDifficulty());
                    newCustomerDifficulty.setCustomerId(customer.getCustomerId());
                    newCustomerDifficulty.setExerciseId(customerExercise.getExerciseId());
                    customerDifficultyMapper.insertCustomerDifficulty(newCustomerDifficulty);
                }
            }
            int result = customerExerciseMapper.updateCustomerExercise(customerExercise);
            if (result > 0) {
                //更新会员信息修改会员成长值
                if (customerExercise.getExerciseType() == ExerciseType.Game.getCode()) {
                    customer.setLevelValue(customer.getLevelValue() + 13);
                }
                if (customerExercise.getExerciseType() == ExerciseType.Video.getCode()) {
                    customer.setLevelValue(customer.getLevelValue() + (customerExercise.getExerciseTime() / 60) * 3);
                }
                customerService.updateCustomerInfo(customer);
                //如果发现当前会员没有未完成的训练了，自动更新下一次训练的开启时间
                CustomerExercise query = new CustomerExercise();
                query.setCustomerId(customerExercise.getCustomerId());
                query.setOrderId(customerExercise.getOrderId());
                List<CustomerExercise> lstCustomerExercise = customerExerciseMapper.selectCustomerExerciseList(query);
                CustomerExercise noFinish = lstCustomerExercise.stream().filter(item -> item.getStatus() == CustomerExerciseStatus.NoFinish && item.getCountSort().equals(customerExercise.getCountSort())).findFirst().orElse(null);
                if (noFinish == null) {
                    //添加会员训练质量评分
                    CustomerScore customerScore = new CustomerScore();
                    customerScore.setCountSort(customerExercise.getCountSort());
                    customerScore.setCustomerId(customerExercise.getCustomerId());
                    customerScore.setTypeId(customerExercise.getExerciseId());
                    customerScore.setScore(10l);
                    customerScore.setOrderId(customerExercise.getOrderId());
                    customerScore.setScoreType(CustomerScoreType.Exercise);
                    customerScoreMapper.insertCustomerScore(customerScore);
                    CustomerExercise next = new CustomerExercise();
                    next.setCountSort(customerExercise.getCountSort() + 1);
                    List<CustomerExercise> lstNext = lstCustomerExercise.stream().filter(item -> item.getCustomerId().equals(customerExercise.getCustomerId()) && item.getOrderId().equals(customerExercise.getOrderId()) && item.getCountSort().equals(next.getCountSort())).collect(Collectors.toList());
                    if (lstNext.size() > 0) {
                        logger.info("customer_exercise表，更新训练课程入参{}", lstNext);
                        for (CustomerExercise nextExercise : lstNext) {
                            nextExercise.setStatus(CustomerExerciseStatus.NoFinish);
                            //如果是白名单用户直接把opentime设置成当前时间
                            //if (Long.valueOf(NumberConstants.ZERO).equals(customer.getMechanismId())
                            //|| Long.valueOf(NumberConstants.NEGATIVE_ONE).equals(customer.getMechanismId()) )
                            if (Long.valueOf(NumberConstants.ZERO).equals(customer.getMechanismId())) {
                                nextExercise.setOpenTime(DateCalcUtils.addMinute(new Date(), 5));
                            } else {
                                nextExercise.setOpenTime(DateCalcUtils.addHour(new Date(), 8));
                            }
                            int updateCustomerExerciseResult = customerExerciseMapper.updateCustomerExercise(nextExercise);
                            logger.info("customer_exercise表，更新训练课程结果{}", updateCustomerExerciseResult);
                        }
                        customer.setCountSort(lstNext.get(0).getCountSort());
                        boolean updateCustomerResult = customerService.updateCustomerInfo(customer);
                        logger.info("customer表，更新用户课程结果{}", updateCustomerResult);
                    }
                    //每次报告
                    CustomerReportTime customerReportTime = new CustomerReportTime();
                    customerReportTime.setCountSort(customerExercise.getCountSort());
                    customerReportTime.setCustomerId(customer.getCustomerId());
                    customerReportTime.setOrderId(customerExercise.getOrderId());
                    customerReportTime.setGame(0l);
                    customerReportTime.setVideo(0l);
                    customerReportTime.setTimeCount(0l);
                    customerReportTime.setCreateTime(new Date());
                    customerReportTime.setPercentValue(RandomUtil.randomLong(95, 99));
                    List<CustomerExercise> lstNow = lstCustomerExercise.stream().filter(item -> item.getCountSort().equals(customerExercise.getCountSort())).collect(Collectors.toList());
                    for (CustomerExercise tmpData : lstNow) {
                        if (tmpData.getExerciseType() == ExerciseType.Game.getCode()) {
                            customerReportTime.setGame(customerReportTime.getGame() + 1);
                        }
                        if (tmpData.getExerciseType() == ExerciseType.Video.getCode()) {
                            customerReportTime.setVideo(customerReportTime.getVideo() + 1);
                        }
                        if (tmpData.getExerciseTime() != null) {
                            customerReportTime.setTimeCount(customerReportTime.getTimeCount() + tmpData.getExerciseTime());
                        }
                    }
                    customerReportTimeMapper.insertCustomerReportTime(customerReportTime);
                    logger.info("完成每日报告数据" + JSON.toJSONString(customerReportTime));
                    reportVo.setReportType(ReportType.EveryTime);
                    reportVo.setReportId(customerReportTime.getCustomerReportTimeId());
                    //第7次对比报告
                    if (customerExercise.getCountSort() == 7) {
                        Long percent = 0l;
                        List<CustomerExercise> lst7time = lstCustomerExercise.stream().filter(item -> item.getCountSort() == 7 && item.getExerciseType() == ExerciseType.Game.getCode() && item.getResultValue() != null).collect(Collectors.toList());
                        List<CustomerExercise> lst1ttime = lstCustomerExercise.stream().filter(item -> item.getCountSort() == 1 && item.getExerciseType() == ExerciseType.Game.getCode() && item.getResultValue() != null).collect(Collectors.toList());
                        if (lst7time.size() > 0 && lst1ttime.size() > 0) {
                            int value7 = 0;
                            for (CustomerExercise exercise : lst7time) {
                                value7 += exercise.getResultValue();
                            }
                            int value1 = 0;
                            for (CustomerExercise exercise : lst1ttime) {
                                value1 += exercise.getResultValue();
                            }
                            if (value7 - value1 > 0) {
                                percent = RandomUtil.randomLong(95, 99);
                            }
                        }
                        //计算当前用户每缺课一节则减少20%提升概率
                        List<CustomerExercise> lstExpireExercise = lstCustomerExercise.stream().filter(item -> item.getCountSort() <= 7).collect(Collectors.toList());
                        HashSet<Long> setExpireCount = new HashSet<>();
                        for (CustomerExercise exercise : lstExpireExercise) {
                            setExpireCount.add(exercise.getCountSort());
                        }
                        if (setExpireCount.size() > 0) {
                            percent = percent - setExpireCount.size() * 20;
                            if (percent <= 0) {
                                percent = RandomUtil.randomLong(5, 10);
                            }
                        }
                        CustomerReportCycle reportCycle7 = new CustomerReportCycle();
                        reportCycle7.setCustomerId(customerExercise.getCustomerId());
                        reportCycle7.setOrderId(customerExercise.getOrderId());
                        reportCycle7.setPercentValue(percent);
                        reportCycle7.setCreateTime(new Date());
                        reportCycle7.setReportType(ReportType.First_7);
                        customerReportCycleMapper.insertCustomerReportCycle(reportCycle7);
                        logger.info("完成7日报告数据" + JSON.toJSONString(reportCycle7));
                        reportVo.setReportId(reportCycle7.getCustomerReportCycleId());
                        reportVo.setReportType(ReportType.First_7);
                        reportVo.setPercentValue(percent);
                        setCustomerExerciseReport(customerExercise, finishExerciseVO, reportVo);
                        return reportVo;
                    }
                    //第28次对比报告
                    if (customerExercise.getCountSort() % Constants.TIME_28 == 0) {
                        CustomerReportCycle reportCycle28 = new CustomerReportCycle();
                        reportCycle28.setAttention(0l);
                        reportCycle28.setExecute(0l);
                        reportCycle28.setLogic(0l);
                        reportCycle28.setMemory(0l);
                        reportCycle28.setLearnTime(customer.getLearnTime());
                        reportCycle28.setCustomerId(customer.getCustomerId());
                        int day = Math.round((new Date().getTime() - customer.getCreateTime().getTime()) / (24 * 60 * 60 * 1000));
                        reportCycle28.setOnTime((long) day);
                        reportCycle28.setExerciseTime(0l);
                        reportCycle28.setExerciseCount(0l);
                        reportCycle28.setOrderId(customerExercise.getOrderId());
                        reportCycle28.setCreateTime(new Date());
                        for (CustomerExercise data : lstCustomerExercise) {
                            reportCycle28.setAttention(reportCycle28.getAttention() + data.getAttention());
                            reportCycle28.setExecute(reportCycle28.getExecute() + data.getExecute());
                            reportCycle28.setLogic(reportCycle28.getLogic() + data.getLogic());
                            reportCycle28.setMemory(reportCycle28.getMemory() + data.getMemory());
                            if (data.getExerciseTime() != null) {
                                reportCycle28.setExerciseTime(reportCycle28.getExerciseTime() + data.getExerciseTime());
                            }
                            if (data.getStatus() == CustomerExerciseStatus.Finished) {
                                reportCycle28.setExerciseCount(reportCycle28.getExerciseCount() + 1);
                            }
                            reportCycle28.setReportType(ReportType.Time_28);
                            reportCycle28.setPercentValue(RandomUtil.randomLong(95, 99));
                        }
                        Date beginTime = lstCustomerExercise.get(0).getCreateTime();
                        int days = DateUtils.differentDaysByMillisecond(beginTime, new Date());
                        if (days > 41) {
                            reportCycle28.setTimeScore(60l);
                        }
                        if (days >= 36 && days <= 40) {
                            reportCycle28.setTimeScore(RandomUtil.randomLong(60, 80));
                        }
                        if (days >= 31 && days <= 35) {
                            reportCycle28.setTimeScore(RandomUtil.randomLong(80, 90));
                        }
                        if (days <= 30) {
                            reportCycle28.setTimeScore(RandomUtil.randomLong(90, 100));
                        }
                        //获取最长视频时间
                        List<CustomerExercise> lstExerciseTime = lstCustomerExercise.stream().filter(item -> item.getExerciseTime() != null).collect(Collectors.toList());
                        lstExerciseTime.sort(Comparator.comparing(item -> item.getExerciseTime()));
                        CustomerExercise data = lstExerciseTime.get(lstExerciseTime.size() - 1);
                        reportCycle28.setLongestTime(data.getExerciseTime());
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                        reportCycle28.setLongestDay(sdf.format(data.getEndTime()));
                        //获取最短的游戏时间
                        List<CustomerExercise> lstGameTime = lstCustomerExercise.stream().filter(item -> item.getExerciseTime() != null && item.getExerciseType() == ExerciseType.Game.getCode()).collect(Collectors.toList());
                        lstGameTime.sort(Comparator.comparing(item -> item.getExerciseTime()));
                        reportCycle28.setShortestTime(lstGameTime.get(0).getExerciseTime());
                        customerReportCycleMapper.insertCustomerReportCycle(reportCycle28);
                        logger.info("完成28日报告数据" + JSON.toJSONString(reportCycle28));
                        reportVo.setReportId(reportCycle28.getCustomerReportCycleId());
                        reportVo.setReportType(ReportType.Time_28);
                        setCustomerExerciseReport(customerExercise, finishExerciseVO, reportVo);
                        logger.info("完成报告返回数据" + JSON.toJSONString(reportVo));
                        return reportVo;
                    }

                    //完成脑力训练，添加积分
                    if (customerExercise.getExerciseType() == ExerciseType.Game.getCode()) {
                        addScoreRecord(customerExercise, customer);
                    }
                }
                setCustomerExerciseReport(customerExercise, finishExerciseVO, reportVo);
                return reportVo;
            }
        } catch (Exception e) {
            logger.error("完成训练失败！", e);
        }
        return reportVo;
    }

    @Transactional(rollbackFor = Exception.class)
    public Integer addScoreRecord(CustomerExercise customerExercise, Customer customer) {
        long ts = DateUtils.getTimeMillis();
        Integer maxRecordId = scoreRecordService.getMaxRecordId();
        maxRecordId = null == maxRecordId ? NumberConstants.ONE : maxRecordId + 1;
        ScoreRecord scoreRecord = constructScoreRecord(maxRecordId, customerExercise, ScoreTypeEnum.COMPLETED_TRAIN);
        int insertResult = scoreRecordService.insertScoreRecord(scoreRecord);
        Long score = null == customer.getScore() ? Long.valueOf(NumberConstants.ZERO) : customer.getScore();
        score = score + scoreRecord.getScore();

        logger.info("ts{}，新增完成训练积分结果{}", ts, insertResult);
        CustomerExercise exercise = new CustomerExercise();
        exercise.setCustomerId(customerExercise.getCustomerId());
        exercise.setOrderId(customerExercise.getOrderId());
        List<CustomerExercise> customerExerciseList = customerExerciseMapper.selectCustomerExerciseList(exercise);
        Long countSort = customerExercise.getCountSort();
        if (countSort > NumberConstants.TWO) {

            Integer persistenceDays = 0;
            for (Long i = countSort ; i >= 1; i--) {
                final Long countSortTmp = i;
                List<CustomerExercise> exerciseList = customerExerciseList.stream().filter(item -> item.getCountSort().equals(countSortTmp)).collect(Collectors.toList());
                boolean allFinishedFlag = true;
                for (CustomerExercise exerciseItem : exerciseList) {
                    if (exerciseItem.getStatus() != CustomerExerciseStatus.Finished) {
                        allFinishedFlag = false;
                        break;
                    }
                }
                if (allFinishedFlag) {
                    persistenceDays++;
                }else{
                    break;
                }
            }

            if (persistenceDays > 0 && persistenceDays % NumberConstants.THREE == 0) {
                Integer maxRecordId2 = scoreRecordService.getMaxRecordId();
                maxRecordId2 = null == maxRecordId ? NumberConstants.ONE : maxRecordId + 1;
                scoreRecord = constructScoreRecord(maxRecordId2, customerExercise, ScoreTypeEnum.CONTINUE_3_DAYS_COMPLETED_TRAIN);
                score = score + scoreRecord.getScore();
                int continueResult = scoreRecordService.insertScoreRecord(scoreRecord);
                logger.info("ts{}，新增连续3天完成训练积分结果{}", ts, continueResult);
            }
        }

        customer.setScore(score);
        customerService.updateCustomer(customer);
        customerService.refreshToken(ts,customer);

        return insertResult;
    }

    private ScoreRecord constructScoreRecord(Integer recordId, CustomerExercise customerExercise, ScoreTypeEnum scoreTypeEnum) {
        ScoreRecord scoreRecord = new ScoreRecord();
        Long customerId = customerExercise.getCustomerId();
        String strCustomerId = null == customerId ? "" : String.valueOf(customerId);
        Date now = DateUtils.getNowDate();
        scoreRecord.setRecordId(Long.valueOf(recordId));
        scoreRecord.setCustomerId(customerExercise.getCustomerId());
        scoreRecord.setOrderNo(customerExercise.getOrderId());
        scoreRecord.setCountSort(customerExercise.getCountSort());
        scoreRecord.setScoreType(scoreTypeEnum.getCode());
        scoreRecord.setScore(Long.valueOf(scoreTypeEnum.getScore()));
        scoreRecord.setScoreDesc(scoreTypeEnum.getInfo());
        scoreRecord.setYn(YNEnum.NO.getCode());
        scoreRecord.setCreateUser(strCustomerId);
        scoreRecord.setCreateTime(now);
        scoreRecord.setUpdateUser(strCustomerId);
        scoreRecord.setUpdateTime(now);

        return scoreRecord;
    }

    @Override
    public boolean customerOrderReset(Customer customer, CustomerExercise customerExercise) {
        //更新当前订单状态为已完成 查找下一个订单并修改训练状态
        ExerciseOrder exerciseOrder = exerciseOrderMapper.selectExerciseOrderByOrderId(customerExercise.getOrderId());
        exerciseOrder.setStatus(PayStatus.Finish);
        exerciseOrder.setUpdateTime(new Date());
        exerciseOrderMapper.updateExerciseOrder(exerciseOrder);
        ExerciseOrder queryOrder = new ExerciseOrder();
        queryOrder.setCustomerId(customer.getCustomerId());
        queryOrder.setStatus(PayStatus.Paid);
        List<ExerciseOrder> lstOrder = exerciseOrderMapper.selectExerciseOrderList(queryOrder);
        if (lstOrder.size() > 0) {
            ExerciseOrder nextOrder = lstOrder.get(0);
            nextOrder.setStatus(PayStatus.Exercise);
            nextOrder.setUpdateTime(new Date());
            exerciseOrderMapper.updateExerciseOrder(nextOrder);
            CustomerExercise queryExercise = new CustomerExercise();
            queryExercise.setCustomerId(customer.getCustomerId());
            queryExercise.setOrderId(nextOrder.getOrderId());
            queryExercise.setCountSort(1l);
            List<CustomerExercise> lstExercise = customerExerciseMapper.selectCustomerExerciseList(queryExercise);
            Date nowDate = new Date();
            for (CustomerExercise nextExercise : lstExercise) {
                nextExercise.setStatus(CustomerExerciseStatus.NoFinish);
                if (customer.getMechanismId().equals(0l)) {
                    nowDate = DateCalcUtils.addMinute(new Date(), 5);
                    nextExercise.setOpenTime(DateCalcUtils.addMinute(new Date(), 5));
                } else {
                    nowDate = DateCalcUtils.addHour(new Date(), 8);
                    nextExercise.setOpenTime(nowDate);
                }
                customerExerciseMapper.updateCustomerExercise(nextExercise);
            }
            ChatMain queryChatMain = new ChatMain();
            queryChatMain.setCustomerId(customer.getCustomerId());
            List<ChatMain> lstChatMain = chatMainMapper.selectChatMainList(queryChatMain);
            if (lstChatMain.size() > 0) {
                ChatMain chatMain = lstChatMain.get(0);
                chatMain.setNextOpenTime(nowDate);
                chatMainMapper.updateChatMain(chatMain);
            }
            customer.setCountSort(1l);
            boolean result = customerService.updateCustomerInfo(customer);
            if (result) {
                return true;
            }
        }
        return false;
    }

    public boolean customerExerciseNextReset(CustomerExercise customerExercise, Customer customer) {
        try {
            CustomerExercise next = new CustomerExercise();
            next.setCustomerId(customerExercise.getCustomerId());
            next.setOrderId(customerExercise.getOrderId());
            next.setCountSort(customerExercise.getCountSort() + 1);
            List<CustomerExercise> lstNext = customerExerciseMapper.selectCustomerExerciseList(next);
            if (lstNext.size() > 0) {
                for (CustomerExercise nextExercise : lstNext) {
                    nextExercise.setStatus(CustomerExerciseStatus.NoFinish);
                    //如果是白名单用户直接把opentime设置成当前时间
                    if (customer.getMechanismId() != 0) {
                        nextExercise.setOpenTime(DateCalcUtils.addHour(new Date(), 8));
                    } else {
                        nextExercise.setOpenTime(new Date());
                    }
                    customerExerciseMapper.updateCustomerExercise(nextExercise);
                }
                customer.setCountSort(lstNext.get(0).getCountSort());
                customerService.updateCustomerInfo(customer);
            }
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return false;
        }
    }

    @Override
    public void customerExerciseExpired() {
        try {
            long tid = DateUtils.getTimeMillis();
            Date beginDate = new Date();
            logger.info("tid：{},【修改会员训练过期状态】,开始时间：{}", tid, DateUtils.getTime());
            //查询出当前已符合过期条件的训练
            List<CustomerExercise> lstTmpData = customerExerciseMapper.selectCustomerExerciseExpired();
            List<CustomerExercise> lstExpiredExercise = new ArrayList<>();
            for (CustomerExercise tmpData : lstTmpData) {
                ExerciseOrder order = exerciseOrderMapper.selectExerciseOrderByOrderId(tmpData.getOrderId());
                if (order != null) {
                    if (order.getStatus() == PayStatus.Exercise) {
                        lstExpiredExercise.add(tmpData);
                    }
                }
            }
            Map<Long, CustomerExercise> mCustomerExercise = new HashMap<>();
            for (CustomerExercise customerExercise : lstExpiredExercise) {
                customerExercise.setStatus(CustomerExerciseStatus.expired);
                if (!mCustomerExercise.containsKey(customerExercise.getCustomerId())) {
                    mCustomerExercise.put(customerExercise.getCustomerId(), customerExercise);
                }
                logger.info("1、过期的会员ID {}, 会员过期的训练集合{}", customerExercise.getCustomerId(), JSON.toJSONString(customerExercise));
            }
            //根据会员信息分组，并查询出下一个未开启的训练
            for (Map.Entry<Long, CustomerExercise> entry : mCustomerExercise.entrySet()) {
                //会员ID，会员当前训练次数的count + 1，当前没开启的训练记录，会员订单编号
                CustomerExercise query = new CustomerExercise();
                query.setCustomerId(entry.getKey());
                query.setStatus(CustomerExerciseStatus.NoOpen);
                Long countSort = mCustomerExercise.get(entry.getKey()).getCountSort();
                Long nextCountSort = countSort + 1;
                query.setOrderId(mCustomerExercise.get(entry.getKey()).getOrderId());
                query.setCountSort(nextCountSort);
                List<CustomerExercise> lstOpen = customerExerciseMapper.selectCustomerExerciseList(query);
                if (lstOpen.size() > 0) {
                    Date nowDate = new Date();
                    for (CustomerExercise nextExercise : lstOpen) {
                        nextExercise.setStatus(CustomerExerciseStatus.NoFinish);
                        nextExercise.setOpenTime(nowDate);
                    }
                    logger.info("2、过期的会员ID {}, 会员要开启的训练集合{}", entry.getKey(), JSON.toJSONString(lstOpen));
                    ChatMain queryChatMain = new ChatMain();
                    queryChatMain.setCustomerId(entry.getKey());
                    List<ChatMain> lstChatMain = chatMainMapper.selectChatMainList(queryChatMain);
                    if (lstChatMain.size() > 0) {
                        ChatMain chatMain = lstChatMain.get(0);
                        chatMain.setNextOpenTime(nowDate);
                        int result = chatMainMapper.updateChatMain(chatMain);
                        logger.info("3、青竹聊天主表{},更新结果{}", JSON.toJSONString(chatMain), result);
                    }
                    //重置会员的countSort
                    Customer customer = customerService.selectCustomerByCustomerId(entry.getKey());
                    customer.setCountSort(nextCountSort);
                    customerService.updateCustomerInfo(customer);
                    logger.info("4、会员ID {}，会员更新后count {}，会员当前训练count {}，", customer.getCustomerId(), customer.getCountSort(), countSort);
                    lstExpiredExercise.addAll(lstOpen);
                }
                //如果有28次训练过期的话则修改当前训练订单的状态并修改countSort
                if (countSort % Constants.TIME_28 == 0) {
                    Customer customer = customerService.selectCustomerByCustomerId(entry.getKey());
                    customerOrderReset(customer, mCustomerExercise.get(entry.getKey()));
                }
            }
            for (CustomerExercise exercise : lstExpiredExercise) {
                customerExerciseMapper.updateCustomerExercise(exercise);
            }
            logger.info("tid：{},【修改会员训练过期状态】,结束时间：{}", tid, DateUtils.getTime());
            Date endDate = new Date();
            logger.info("tid：{},【修改会员训练过期状态】,耗时：{}", tid, DateUtils.differentMinuteByMillisecond(beginDate, endDate));
        } catch (Exception e) {
            logger.error("定时任务异常", e);
        }
    }

    @Override
    public NowCustomerExercise getNowCustomerExerciseList(Customer customer) {
        //获取用户当前训练中的订单如果没有训练中的订单则拿出已完成的订单
        ExerciseOrder queryOrder = new ExerciseOrder();
        queryOrder.setStatus(PayStatus.Exercise);
        queryOrder.setCustomerId(customer.getCustomerId());
        List<ExerciseOrder> lstOrder = exerciseOrderMapper.selectExerciseOrderList(queryOrder);
        if (lstOrder.size() == 0) {
            queryOrder.setStatus(PayStatus.Finish);
            lstOrder = exerciseOrderMapper.selectExerciseOrderList(queryOrder);
        }
        ExerciseOrder nowOrder = lstOrder.get(lstOrder.size() - 1);
        CustomerExercise query = new CustomerExercise();
        query.setCustomerId(customer.getCustomerId());
        query.setOrderId(nowOrder.getOrderId());
        List<CustomerExercise> lstCustomerExercise = customerExerciseMapper.selectCustomerExerciseList(query);
        NowCustomerExercise nowCustomerExercise = new NowCustomerExercise();
        nowCustomerExercise.setOrder(nowOrder);
        nowCustomerExercise.setLstCustomerExercise(lstCustomerExercise);
        return nowCustomerExercise;
    }

    @Override
    public Map<String, Long> getProgressMap(Customer customer) {
        Map<String, Long> map = new HashMap<>(2);
        List<CustomerExercise> customerExerciseList = getCustomerExerciseList(customer, CustomerExerciseStatus.Finished);
        // if (org.apache.commons.collections.CollectionUtils.isEmpty(customerExerciseList)) {
        //     return null;
        // }
        //OptionalLong optionalLong = customerExerciseList.stream().mapToLong(CustomerExercise::getCountSort).min();
        Long completedCourseNo = getCompletedCourseNo(customerExerciseList);
        map.put(Constants.MARK_COMPLETED_DAYS, completedCourseNo);
        List<CustomerExercise> allCustomerExerciseList = getCustomerExerciseList(customer, null);
        OptionalLong maxOptionalLong = allCustomerExerciseList.stream().mapToLong(CustomerExercise::getCountSort).max();
        List<CustomerExercise> expiredCustomerExerciseList = getCustomerExerciseList(customer, CustomerExerciseStatus.expired);
        List<CustomerExercise> distinctCustomerExerciseList = getDistinctCustomerExerciseList(expiredCustomerExerciseList);
        Integer expiredSize = org.apache.commons.collections.CollectionUtils.isEmpty(distinctCustomerExerciseList) ? 0 : distinctCustomerExerciseList.size();
        Long remind = maxOptionalLong.getAsLong() - expiredSize - completedCourseNo;
        map.put(Constants.MARK_REMIND_DAYS, remind);
        return map;
    }

    private List<CustomerExercise> getDistinctCustomerExerciseList(List<CustomerExercise> expiredCustomerExerciseList) {
        if (org.apache.commons.collections.CollectionUtils.isEmpty(expiredCustomerExerciseList)) {
            return null;
        }
        List<CustomerExercise> result = new LinkedList<>();
        for (CustomerExercise customerExercise : expiredCustomerExerciseList) {
            boolean b = result.stream().anyMatch(u -> u.getCountSort().equals(customerExercise.getCountSort()));
            if (!b) {
                result.add(customerExercise);
            }
        }
        return result;
    }

    private Long getCompletedCourseNo(List<CustomerExercise> finishedCustomerExerciseList) {
        if (CollectionUtils.isEmpty(finishedCustomerExerciseList)) {
            return 0l;
        }
        Map<Long, List<CustomerExercise>> listMap = finishedCustomerExerciseList.stream().collect(Collectors.groupingBy(CustomerExercise::getCountSort));
        List<CustomerExercise> list = new ArrayList<>();
        Set<Long> longs = listMap.keySet();
        for (Long aLong : longs) {
            List<CustomerExercise> customerExerciseList = listMap.get(aLong);
            boolean b = customerExerciseList.stream().allMatch(exercise -> exercise.getStatus() == CustomerExerciseStatus.Finished);
            if (b && customerExerciseList.size() > 1) {
                list.addAll(customerExerciseList);
            }
        }

        if (org.apache.commons.collections.CollectionUtils.isEmpty(list)) {
            return Long.valueOf(0);
        }

        return Long.valueOf(list.size() / NumberConstants.TWO);
    }

    /**
     * 设置青竹聊天状态
     *
     * @param chatRecordId
     * @param status
     */
    public void setChatRecord(Long chatRecordId, Integer status, Integer inputType) {
        ChatRecord chatRecord = chatRecordMapper.selectChatRecordById(chatRecordId);
        ChatContent chatContent = JSONObject.parseObject(chatRecord.getContent(), ChatContent.class);
        chatContent.setStatus(status);
        String jsonString = JSON.toJSONString(chatContent);
        chatRecord.setContent(jsonString);
        Integer answerType = getAnswerType(status, inputType);
        chatRecord.setAnswerType(answerType);
        chatRecordMapper.updateChatRecord(chatRecord);
    }

    private Integer getAnswerType(Integer status, Integer inputType) {
        if (InputTypeEnum.EXERCISE_CARD_VIDEO.getCode().equals(inputType)) {
            if (status == 2) {
                return YNEnum.YES.getCode();
            }
            return YNEnum.NO.getCode();
        }
        return status;
    }

    /**
     * 设置聊天装和报告状态
     */
    public void setCustomerExerciseReport(CustomerExercise customerExercise, FinishExerciseVO finishExerciseVO, CustomerReportVO reportVo) {
        if (customerExercise.getStatus() == CustomerExerciseStatus.NoFinish) {
            setChatRecord(finishExerciseVO.getChatRecordId(), 3, finishExerciseVO.getInputType());
            reportVo.setStatus(BusinessStatus.FAIL);
        }
        if (customerExercise.getStatus() == CustomerExerciseStatus.Finished) {
            setChatRecord(finishExerciseVO.getChatRecordId(), 2, finishExerciseVO.getInputType());
            reportVo.setStatus(BusinessStatus.SUCCESS);
        }
        reportVo.setCountSort(customerExercise.getCountSort());
        reportVo.setCustomerExerciseId(customerExercise.getCustomerExerciseId());
    }
}
